package gps.methods;

import gps.Node;
import gps_api.Rule;
import gps_api.State;

import java.util.Stack;

public class BaseNode implements Node{
	private Node ancestor;
	private Rule rule;
	private State state;
	private Integer level;
	private Double cost;
	private Double heu;
	private Double f;
	
	public BaseNode(State state){
		this.state=state;
		this.ancestor= null;
		this.rule= null;
		this.cost=0.0;
		this.heu=0.0;
		this.f= 0.0;
		this.level=0;
	}
	
	public BaseNode(Node node, State state, Rule rule, Double cost, Double heu){
		this.ancestor= node;
		this.state= state;
		this.rule= rule;
		this.cost= node.getCost() + cost;
		this.heu= heu;
		this.f= this.cost + this.heu;
		this.level=node.getLevel() + 1;
		/* Consistency */
		//this.f= Math.max(this.f, node.getF());
	}

	
	@Override
	public boolean hasEqualAncestor(State state){
		boolean ans= false;
		Node node=this;
		
		while(!ans && node!=null){
			if(node.getState().equals(state)){
				ans=true;
			}
			node=node.getAncestor();
		}
		return ans;
	}
	
	@Override
	public void printSolution(){
		Stack<Node> trackSol= new Stack<Node>();
		Node node=this;
		int i=0;
		
		while(node!=null){
			trackSol.push(node);
			node= node.getAncestor();
		}
		
		while(!trackSol.isEmpty()){
			node= trackSol.pop();
			if(node.getRule()!=null){
				System.out.println("Rule "+ i + ": " + node.getRule().toString());	
			}
			System.out.println(node.getState().toString());
			i++;
		}
	}
	
	@Override
	public Node getAncestor() {
		return ancestor;
	}

	@Override
	public Rule getRule() {
		return rule;
	}

	@Override
	public State getState() {
		return state;
	}
	
	@Override
	public Double getCost() {
		return cost;
	}

	public void setCost(Double cost) {
		this.cost = cost;
	}

	public Double getHeu() {
		return heu;
	}

	public void setHeu(Double heu) {
		this.heu = heu;
	}

	public Double getF() {
		return f;
	}

	public void setF(Double f) {
		this.f = f;
	}

	@Override
	public boolean equals(Object arg0){
		boolean ans=false;
		BaseNode node;
		if(arg0 instanceof BaseNode){
			node=(BaseNode)arg0;
			ans= this.state.equals(node.getState());
		}
		
		return ans;
	}

	@Override
	public Integer getLevel() {
		return level;
	}

	@Override
	public int compareTo(Node o) {
		int ans=0;
		
		if(this.f< o.getF()){
			ans= -1;
		}else if(this.f== o.getF()){
			if(this.heu< o.getHeu()){
				ans= -1;
			}else if(this.heu> o.getHeu()){
				ans=1;
			}
		}else{
			ans= 1;
		}
		
		return ans;
	}

}
